package com.cy;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.cy.service.ConsumerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * @SpringBootApplication 注解描述的类为springboot工程的启动类(一个springboot
 * 工程这样的启动类只能有一份),这个启动类本质上也是一个配置类,在配置类在启动时
 * 会读取spring.factories配置文件,进行springboot初始配置.
 */
//@EnableDiscoveryClient //启动服务发现机制 (可选)
@EnableFeignClients //启动feign方式调用机制
@SpringBootApplication
public class NacosConsumerApplication {//服务消费方
    public static void main(String[] args) {
        SpringApplication.run(NacosConsumerApplication.class,args);
    }
    /**
     * RestTemplate封装了Http请求方式,我们可以直接通过
     * 此对象远程访问另一个http服务.这个对象在springboot工程启动时并没有初始化,
     * 所以需要我们手动创建一个这样的对象,并将此对象交给spring管理(@Bean)
     * @Bean 应用说明:
     * 1)用于在@Configuration注解描述的类中描述方法
     * 2)此注解描述的方法用于创建一个第三方对象并交给spring管理
     * 3)Spring存储时这个bean时,默认为bean起的名字为方法名
     */
    @Bean
    public RestTemplate restTemplate(){//bean的名字默认为方法名
        return new RestTemplate();
    }

    @Bean
    @LoadBalanced //注解描述RestTemplate对象时,表示让restTemplate具备了负载均衡的特性
    public RestTemplate loadBalancedRestTemplate(){//bean的名字默认为方法名
        return new RestTemplate();
    }


    @Value("${spring.application.name}")
    private String appName;

    @RestController
    public class ConsumerController{
        @Autowired
        private RestTemplate restTemplate;

        @Autowired
        private RestTemplate loadBalancedRestTemplate;

        /**此对象可以基于服务名,找到具体的服务实例(ServiceInstance),找到了
         * 实例后就可以获取实例对应的ip地址(host)和端口号,拿到ip
         * 地址和端口号以后就可以通过restTemplate调用对应的服务了
         * */
        @Autowired
        private LoadBalancerClient loadBalancerClient;

        @Autowired
        private ConsumerService consumerService;


        /**直接通过ip地址和端口访问远端服务（可以不需要nacos）
         * 缺陷:
         * 1)ip和Port可能会发生变化
         * 2)只能访问一个服务实例,不支持负载均衡
         * */
        @GetMapping("/consumer/doRestEcho1")
        public String doRestEcho(){
            //服务提供的的url
            String url="http://localhost:8081/provider/echo/"+appName;
            //向服务提供方法发起请求
            return restTemplate.getForObject(
                    url,//要请求的服务的地址
                    String.class);//String.class为请求服务的响应结果类型(responseType)
        }

        /**
         * 通过loadBalancerClient获取服务实例,然后构建url,再通过
         * restTemplate进行访问,可以实现负载均衡,优势是直观,但代码量
         * 稍微多一些.
         * @return
         */
        @GetMapping("/consumer/doRestEcho2")
        public String doRestLoadBalancerClientEcho(){
            //基于服务名获取服务实例 (不同服务实例端口肯定不同),构建url
            ServiceInstance serviceInstance=//8081,8082
                    loadBalancerClient.choose("nacos-provider");
            String serviceIp=serviceInstance.getHost();//ip
            int servicePort=serviceInstance.getPort();//port
            String url=String.format("http://%s:%s/provider/echo/%s",serviceIp,servicePort,appName);
            //向服务提供方发起http请求,获取响应数据
            return restTemplate.getForObject(
                    url,//要请求的服务的地址
                    String.class);//String.class为请求服务的响应结果类型(responseType)
        }

        /**
         * 在RestTemplate对象构建时,通过@LoadBalance注解,告诉spring框架
         * 赋予RestTemplate对象负载均衡特性.在定义要访问的服务url时,直接
         * 可以通过服务名找到对应的服务实例进行访问.
         * @return
         */
        @GetMapping("/consumer/doRestEcho3")
        public String doLoadBalanceRestTemplateEcho(){
            String url=String.format("http://nacos-provider/provider/echo/%s",appName);
            //向服务提供方发起http请求,获取响应数据
            return loadBalancedRestTemplate.getForObject(
                    url,//要请求的服务的地址
                    String.class);//String.class为请求服务的响应结果类型(responseType)
        }
        @Autowired
        private ConsumerHttpApi consumerHttpApi;

        @GetMapping("/consumer/echo/")
        public String echoMsg(){

            consumerService.doGetResource();

            System.out.println("consumerHttpApi="+consumerHttpApi.getClass().getName());
            //feign方式的调用
            return consumerHttpApi.echoMsg(appName);
        }

        @GetMapping("/consumer/doFindById")
        @SentinelResource("findById")
        public String doFindById(@RequestParam Integer id) {

            return "the hot resource id is: " + id;

        }

    }
}